﻿using BooksLib.Models;
using BooksLib.Repositories;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;

namespace BooksLib.Services
{
    public class BooksService : IBooksService
    {
        // ObservableCollection<T>表示一个动态数据集合，它可在添加、删除项目或刷新整个列表时提供通知
        private ObservableCollection<Book> _books = new ObservableCollection<Book>();
       
        //在构造函数中依赖注入存储库，使得业务处理与数据访问分离
        private IBooksRepository _booksRepository;
        public BooksService(IBooksRepository repository)
        {
            //将外部存储库实例注入内部私有变量
             _booksRepository = repository;
        }

        /// <summary>
        /// 异步获取所有书
        /// </summary>
        /// <returns>返回异步任务（无返回值）</returns>
        public async Task LoadBooksAsync()
        {
            //若私有数据集有数据，则无须再次导入
            if (_books.Count > 0) return;

            //从存储库中调用异步方法获取所有数据
            IEnumerable<Book> books = await _booksRepository.GetItemsAsync();

            //为了确保数据集中所有数据都来自存储库，将原私有数据集清除。
            _books.Clear();
            
            //将从仓储库中读取到的数据加入私有数据集中
            foreach (var b in books)
            {
                _books.Add(b);
            }
        }

        /// <summary>
        /// 从私有ObservableCollection数据集中根据指定id获取书
        /// </summary>
        /// <param name="bookId"></param>
        /// <returns>返回指定id的书籍</returns>
        public Book GetBook(int bookId)
        {
            //按指定id查询私有数据集，返回对应书/默认值。如果有两个及以上的数据
            return _books.Where(b => b.BookId == bookId).SingleOrDefault();
        }


        /// <summary>
        /// 异步添加/更新书籍到存储库
        /// </summary>
        /// <param name="book"></param>
        /// <returns></returns>
        public async Task<Book> AddOrUpdateBookAsync(Book book)
        {
            //如果book为null,抛空异常
            if (book is null) throw new ArgumentNullException(nameof(book));

            //设置一个Book变量updated，用以返回在添加或删除操作后从存储库中传回的书
            Book updated = null;

            //根据bookid判断用户操作是添加还是更新，从而采取不同的仓储策略
            if (book.BookId == 0)
            {
                //添加操作，调用存储库添加方法，将书添加到存储库
                updated = await _booksRepository.AddAsync(book);
                //同步添加到私有数据集中
                _books.Add(updated);
            }
            else
            {
                //更新操作调用存储库添加方法，将书更新到存储库
                updated = await _booksRepository.UpdateAsync(book);
                //如果更新存储库返回null，抛出无效操作异常
                if (updated == null) throw new InvalidOperationException();
                
                //同步处理私有数据集
                //检索私有数据集中对应的原数据
                Book old = _books.Where(b => b.BookId == updated.BookId).Single();
                //找出其索引
                int ix = _books.IndexOf(old);
                //将其从数据集中移除
                _books.RemoveAt(ix);
                //将新数据插入到指定索引位置
                _books.Insert(ix, updated);
            }
            return updated;
        }

        /// <summary>
        /// Book只读属性，对外公有
        /// </summary>
        public IEnumerable<Book> Books
        {
            get { return _books; }
        }
    }
}
